home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / emul_op.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-10  |  15.3 KB  |  553 lines

  1. /*
  2.  *  emul_op.cpp - 68k opcodes for ROM patches
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <string.h>
  22. #include <stdio.h>
  23.  
  24. #include "sysdeps.h"
  25. #include "cpu_emulation.h"
  26. #include "main.h"
  27. #include "macos_util.h"
  28. #include "rom_patches.h"
  29. #include "rsrc_patches.h"
  30. #include "xpram.h"
  31. #include "adb.h"
  32. #include "timer.h"
  33. #include "clip.h"
  34. #include "serial.h"
  35. #include "sony.h"
  36. #include "disk.h"
  37. #include "cdrom.h"
  38. #include "scsi.h"
  39. #include "video.h"
  40. #include "audio.h"
  41. #include "ether.h"
  42. #include "extfs.h"
  43. #include "emul_op.h"
  44.  
  45. #ifdef ENABLE_MON
  46. #include "mon.h"
  47. #endif
  48.  
  49. #define DEBUG 0
  50. #include "debug.h"
  51.  
  52.  
  53. /*
  54.  *  Execute EMUL_OP opcode (called by 68k emulator or Illegal Instruction trap handler)
  55.  */
  56.  
  57. void EmulOp(uint16 opcode, M68kRegisters *r)
  58. {
  59.     D(bug("EmulOp %04x\n", opcode));
  60.     switch (opcode) {
  61.         case M68K_EMUL_BREAK: {                // Breakpoint
  62.             printf("*** Breakpoint\n");
  63.             printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n"
  64.                    "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n"
  65.                    "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n"
  66.                    "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n"
  67.                    "sr %04x\n",
  68.                    r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7],
  69.                    r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7],
  70.                    r->sr);
  71. #ifdef ENABLE_MON
  72.             char *arg[4] = {"mon", "-m", "-r", NULL};
  73.             mon(3, arg);
  74. #endif
  75.             QuitEmulator();
  76.             break;
  77.         }
  78.  
  79.         case M68K_EMUL_OP_SHUTDOWN:            // Quit emulator
  80.             QuitEmulator();
  81.             break;
  82.  
  83.         case M68K_EMUL_OP_RESET: {            // MacOS reset
  84.             D(bug("*** RESET ***\n"));
  85.             TimerReset();
  86.             EtherReset();
  87.             AudioReset();
  88.  
  89.             // Create BootGlobs at top of memory
  90.             Mac_memset(RAMBaseMac + RAMSize - 4096, 0, 4096);
  91.             uint32 boot_globs = RAMBaseMac + RAMSize - 0x1c;
  92.             WriteMacInt32(boot_globs + 0x00, RAMBaseMac);    // First RAM bank
  93.             WriteMacInt32(boot_globs + 0x04, RAMSize);
  94.             WriteMacInt32(boot_globs + 0x08, 0xffffffff);    // End of bank table
  95.             WriteMacInt32(boot_globs + 0x0c, 0);
  96.  
  97.             // Setup registers for boot routine
  98.             r->d[0] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x18);    // AddrMapFlags
  99.             r->d[1] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x1c);    // UnivROMFlags
  100.             r->d[2] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x10);    // HWCfgFlags/IDs
  101.             if (FPUType)
  102.                 r->d[2] |= 0x10000000;                                    // Set FPU flag if FPU present
  103.             else
  104.                 r->d[2] &= 0xefffffff;                                    // Clear FPU flag if no FPU present
  105.             r->a[0] = ROMBaseMac + UniversalInfo + ReadMacInt32(ROMBaseMac + UniversalInfo);// AddrMap
  106.             r->a[1] = ROMBaseMac + UniversalInfo;                        // UniversalInfo
  107.             r->a[6] = boot_globs;                                        // BootGlobs
  108.             r->a[7] = RAMBaseMac + 0x10000;                                // Boot stack
  109.             break;
  110.         }
  111.  
  112.         case M68K_EMUL_OP_CLKNOMEM: {        // Clock/PRAM operations
  113.             bool is_read = r->d[1] & 0x80;
  114.             if ((r->d[1] & 0x78) == 0x38) {
  115.                 // XPRAM
  116.                 uint8 reg = (r->d[1] << 5) & 0xe0 | (r->d[1] >> 10) & 0x1f;
  117.                 if (is_read) {
  118.                     r->d[2] = XPRAM[reg];
  119.                     bool localtalk = !(XPRAM[0xe0] || XPRAM[0xe1]);    // LocalTalk enabled?
  120.                     switch (reg) {
  121.                         case 0x08:
  122.                             if (ROMVersion != ROM_VERSION_32)
  123.                                 r->d[2] &= 0xf8;
  124.                             break;
  125.                         case 0x8a:
  126.                             r->d[2] |= 0x05;    // 32bit mode is always enabled
  127.                             break;
  128.                         case 0xe0:                // Disable LocalTalk (use EtherTalk instead)
  129.                             if (localtalk)
  130.                                 r->d[2] = 0x00;
  131.                             break;
  132.                         case 0xe1:
  133.                             if (localtalk)
  134.                                 r->d[2] = 0xf1;
  135.                             break;
  136.                         case 0xe2:
  137.                             if (localtalk)
  138.                                 r->d[2] = 0x00;
  139.                             break;
  140.                         case 0xe3:
  141.                             if (localtalk)
  142.                                 r->d[2] = 0x0a;
  143.                             break;
  144.                     }
  145.                     D(bug("Read XPRAM %02x->%02lx\n", reg, r->d[2]));
  146.                 } else {
  147.                     D(bug("Write XPRAM %02x<-%02lx\n", reg, r->d[2] & 0xff));
  148.                     if (reg == 0x8a && !TwentyFourBitAddressing)
  149.                         r->d[2] |= 0x05;    // 32bit mode is always enabled if possible
  150.                     XPRAM[reg] = r->d[2];
  151.                 }
  152.             } else {
  153.                 // PRAM, RTC and other clock registers
  154.                 uint8 reg = (r->d[1] >> 2) & 0x1f;
  155.                 if (reg >= 0x10 || (reg >= 0x08 && reg < 0x0c)) {
  156.                     if (is_read) {
  157.                         r->d[2] = XPRAM[reg];
  158.                         D(bug("Read XPRAM %02x->%02x\n", reg, XPRAM[reg]));
  159.                     } else {
  160.                         D(bug("Write PRAM %02x<-%02lx\n", reg, r->d[2]));
  161.                         XPRAM[reg] = r->d[2];
  162.                     }
  163.                 } else if (reg < 0x08 && is_read) {
  164.                     uint32 t = TimerDateTime();
  165.                     uint8 b = t;
  166.                     switch (reg & 3) {
  167.                         case 1: b = t >> 8; break;
  168.                         case 2: b = t >> 16; break;
  169.                         case 3: b = t >> 24; break;
  170.                     }
  171.                     r->d[2] = b;
  172.                 } else
  173.                     D(bug("RTC %s op %d, d1 %08lx d2 %08lx\n", is_read ? "read" : "write", reg, r->d[1], r->d[2]));
  174.             }
  175.             r->d[0] = 0;
  176.             r->d[1] = r->d[2];
  177.             break;
  178.         }
  179.  
  180.         case M68K_EMUL_OP_READ_XPRAM:        // Read from XPRAM (ROM10/11)
  181.             D(bug("Read XPRAM %02lx\n", r->d[1]));
  182.             r->d[1] = XPRAM[r->d[1] & 0xff];
  183.             break;
  184.  
  185.         case M68K_EMUL_OP_READ_XPRAM2:        // Read from XPRAM (ROM15)
  186.             D(bug("Read XPRAM %02lx\n", r->d[0]));
  187.             r->d[0] = XPRAM[r->d[0] & 0xff];
  188.             break;
  189.  
  190.         case M68K_EMUL_OP_PATCH_BOOT_GLOBS:    // Patch BootGlobs at startup
  191.             D(bug("Patch BootGlobs\n"));
  192.             WriteMacInt32(r->a[4] - 20, RAMBaseMac + RAMSize);            // MemTop
  193.             WriteMacInt8(r->a[4] - 26, 0);                                // No MMU
  194.             WriteMacInt8(r->a[4] - 25, ReadMacInt8(r->a[4] - 25) | 1);    // No MMU
  195.             r->a[6] = RAMBaseMac + RAMSize;
  196.             break;
  197.  
  198.         case M68K_EMUL_OP_FIX_BOOTSTACK:    // Set boot stack to 3/4 of RAM (7.5)
  199.             r->a[1] = RAMBaseMac + RAMSize * 3 / 4;
  200.             D(bug("Fix boot stack %08x\n", r->a[1]));
  201.             break;
  202.  
  203.         case M68K_EMUL_OP_FIX_MEMSIZE: {    // Set correct logical and physical memory size
  204.             D(bug("Fix MemSize\n"));
  205.             uint32 diff = ReadMacInt32(0x1ef8) - ReadMacInt32(0x1ef4);    // Difference between logical and physical size
  206.             WriteMacInt32(0x1ef8, RAMSize);            // Physical RAM size
  207.             WriteMacInt32(0x1ef4, RAMSize - diff);    // Logical RAM size
  208.             break;
  209.         }
  210.  
  211.         case M68K_EMUL_OP_ADBOP:            // ADBOp() replacement
  212.             ADBOp(r->d[0], Mac2HostAddr(ReadMacInt32(r->a[0])));
  213.             break;
  214.  
  215.         case M68K_EMUL_OP_INSTIME:            // InsTime() replacement
  216.             r->d[0] = InsTime(r->a[0], r->d[1]);
  217.             break;
  218.  
  219.         case M68K_EMUL_OP_RMVTIME:            // RmvTime() replacement
  220.             r->d[0] = RmvTime(r->a[0]);
  221.             break;
  222.  
  223.         case M68K_EMUL_OP_PRIMETIME:        // PrimeTime() replacement
  224.             r->d[0] = PrimeTime(r->a[0], r->d[0]);
  225.             break;
  226.  
  227.         case M68K_EMUL_OP_MICROSECONDS:     // Microseconds() replacement
  228.             Microseconds(r->a[0], r->d[0]);
  229.             break;
  230.  
  231.         case M68K_EMUL_OP_INSTALL_DRIVERS: {// Patch to install our own drivers during startup
  232.             // Install drivers
  233.             D(bug("InstallDrivers\n"));
  234.             InstallDrivers(r->a[0]);
  235.  
  236.             // Install PutScrap() patch
  237.             M68kRegisters r;
  238.             r.d[0] = 0xa9fe;
  239.             r.a[0] = PutScrapPatch;
  240.             Execute68kTrap(0xa647, &r);        // SetToolTrap()
  241.  
  242.             // Setup fake ASC registers
  243.             if (ROMVersion == ROM_VERSION_32) {
  244.                 r.d[0] = 0x1000;
  245.                 Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  246.                 uint32 asc_regs = r.a[0];
  247.                 D(bug("ASC registers at %08lx\n", asc_regs));
  248.                 WriteMacInt8(asc_regs + 0x800, 0x0f);    // Set ASC version number
  249.                 WriteMacInt32(0xcc0, asc_regs);            // Set ASCBase
  250.             }
  251.             break;
  252.         }
  253.  
  254.         case M68K_EMUL_OP_SERD:                // Install serial drivers
  255.             D(bug("InstallSERD\n"));
  256.             InstallSERD();
  257.             break;
  258.  
  259.         case M68K_EMUL_OP_SONY_OPEN:        // Floppy driver functions
  260.             r->d[0] = SonyOpen(r->a[0], r->a[1]);
  261.             break;
  262.  
  263.         case M68K_EMUL_OP_SONY_PRIME:
  264.             r->d[0] = SonyPrime(r->a[0], r->a[1]);
  265.             break;
  266.  
  267.         case M68K_EMUL_OP_SONY_CONTROL:
  268.             r->d[0] = SonyControl(r->a[0], r->a[1]);
  269.             break;
  270.  
  271.         case M68K_EMUL_OP_SONY_STATUS:
  272.             r->d[0] = SonyStatus(r->a[0], r->a[1]);
  273.             break;
  274.  
  275.         case M68K_EMUL_OP_DISK_OPEN:        // Disk driver functions
  276.             r->d[0] = DiskOpen(r->a[0], r->a[1]);
  277.             break;
  278.  
  279.         case M68K_EMUL_OP_DISK_PRIME:
  280.             r->d[0] = DiskPrime(r->a[0], r->a[1]);
  281.             break;
  282.  
  283.         case M68K_EMUL_OP_DISK_CONTROL:
  284.             r->d[0] = DiskControl(r->a[0], r->a[1]);
  285.             break;
  286.  
  287.         case M68K_EMUL_OP_DISK_STATUS:
  288.             r->d[0] = DiskStatus(r->a[0], r->a[1]);
  289.             break;
  290.  
  291.         case M68K_EMUL_OP_CDROM_OPEN:        // CD-ROM driver functions
  292.             r->d[0] = CDROMOpen(r->a[0], r->a[1]);
  293.             break;
  294.  
  295.         case M68K_EMUL_OP_CDROM_PRIME:
  296.             r->d[0] = CDROMPrime(r->a[0], r->a[1]);
  297.             break;
  298.  
  299.         case M68K_EMUL_OP_CDROM_CONTROL:
  300.             r->d[0] = CDROMControl(r->a[0], r->a[1]);
  301.             break;
  302.  
  303.         case M68K_EMUL_OP_CDROM_STATUS:
  304.             r->d[0] = CDROMStatus(r->a[0], r->a[1]);
  305.             break;
  306.  
  307.         case M68K_EMUL_OP_VIDEO_OPEN:        // Video driver functions
  308.             r->d[0] = VideoDriverOpen(r->a[0], r->a[1]);
  309.             break;
  310.  
  311.         case M68K_EMUL_OP_VIDEO_CONTROL:
  312.             r->d[0] = VideoDriverControl(r->a[0], r->a[1]);
  313.             break;
  314.  
  315.         case M68K_EMUL_OP_VIDEO_STATUS:
  316.             r->d[0] = VideoDriverStatus(r->a[0], r->a[1]);
  317.             break;
  318.  
  319.         case M68K_EMUL_OP_SERIAL_OPEN:        // Serial driver functions
  320.             r->d[0] = SerialOpen(r->a[0], r->a[1], r->d[0]);
  321.             break;
  322.  
  323.         case M68K_EMUL_OP_SERIAL_PRIME:
  324.             r->d[0] = SerialPrime(r->a[0], r->a[1], r->d[0]);
  325.             break;
  326.  
  327.         case M68K_EMUL_OP_SERIAL_CONTROL:
  328.             r->d[0] = SerialControl(r->a[0], r->a[1], r->d[0]);
  329.             break;
  330.  
  331.         case M68K_EMUL_OP_SERIAL_STATUS:
  332.             r->d[0] = SerialStatus(r->a[0], r->a[1], r->d[0]);
  333.             break;
  334.  
  335.         case M68K_EMUL_OP_SERIAL_CLOSE:
  336.             r->d[0] = SerialClose(r->a[0], r->a[1], r->d[0]);
  337.             break;
  338.  
  339.         case M68K_EMUL_OP_ETHER_OPEN:        // Ethernet driver functions
  340.             r->d[0] = EtherOpen(r->a[0], r->a[1]);
  341.             break;
  342.  
  343.         case M68K_EMUL_OP_ETHER_CONTROL:
  344.             r->d[0] = EtherControl(r->a[0], r->a[1]);
  345.             break;
  346.  
  347.         case M68K_EMUL_OP_ETHER_READ_PACKET:
  348.             EtherReadPacket((uint8 **)&r->a[0], r->a[3], r->d[3], r->d[1]);
  349.             break;
  350.  
  351.         case M68K_EMUL_OP_SOUNDIN_OPEN:        // Sound input driver functions
  352.             r->d[0] = SoundInOpen(r->a[0], r->a[1]);
  353.             break;
  354.  
  355.         case M68K_EMUL_OP_SOUNDIN_PRIME:
  356.             r->d[0] = SoundInPrime(r->a[0], r->a[1]);
  357.             break;
  358.  
  359.         case M68K_EMUL_OP_SOUNDIN_CONTROL:
  360.             r->d[0] = SoundInControl(r->a[0], r->a[1]);
  361.             break;
  362.  
  363.         case M68K_EMUL_OP_SOUNDIN_STATUS:
  364.             r->d[0] = SoundInStatus(r->a[0], r->a[1]);
  365.             break;
  366.  
  367.         case M68K_EMUL_OP_SOUNDIN_CLOSE:
  368.             r->d[0] = SoundInClose(r->a[0], r->a[1]);
  369.             break;
  370.  
  371.         case M68K_EMUL_OP_SCSI_DISPATCH: {    // SCSIDispatch() replacement
  372.             uint32 ret = ReadMacInt32(r->a[7]);        // Get return address
  373.             uint16 sel = ReadMacInt16(r->a[7] + 4);    // Get selector
  374.             r->a[7] += 6;
  375.             int stack = 0;
  376.             switch (sel) {
  377.                 case 0:        // SCSIReset
  378.                     WriteMacInt16(r->a[7], SCSIReset());
  379.                     stack = 0;
  380.                     break;
  381.                 case 1:        // SCSIGet
  382.                     WriteMacInt16(r->a[7], SCSIGet());
  383.                     stack = 0;
  384.                     break;
  385.                 case 2:        // SCSISelect
  386.                 case 11:    // SCSISelAtn
  387.                     WriteMacInt16(r->a[7] + 2, SCSISelect(ReadMacInt16(r->a[7]) & 0xff));
  388.                     stack = 2;
  389.                     break;
  390.                 case 3:        // SCSICmd
  391.                     WriteMacInt16(r->a[7] + 6, SCSICmd(ReadMacInt16(r->a[7]), Mac2HostAddr(ReadMacInt32(r->a[7] + 2))));
  392.                     stack = 6;
  393.                     break;
  394.                 case 4:        // SCSIComplete
  395.                     WriteMacInt16(r->a[7] + 12, SCSIComplete(ReadMacInt32(r->a[7]), ReadMacInt32(r->a[7] + 4), ReadMacInt32(r->a[7] + 8)));
  396.                     stack = 12;
  397.                     break;
  398.                 case 5:        // SCSIRead
  399.                 case 8:        // SCSIRBlind
  400.                     WriteMacInt16(r->a[7] + 4, SCSIRead(ReadMacInt32(r->a[7])));
  401.                     stack = 4;
  402.                     break;
  403.                 case 6:        // SCSIWrite
  404.                 case 9:        // SCSIWBlind
  405.                     WriteMacInt16(r->a[7] + 4, SCSIWrite(ReadMacInt32(r->a[7])));
  406.                     stack = 4;
  407.                     break;
  408.                 case 10:    // SCSIStat
  409.                     WriteMacInt16(r->a[7], SCSIStat());
  410.                     stack = 0;
  411.                     break;
  412.                 case 12:    // SCSIMsgIn
  413.                     WriteMacInt16(r->a[7] + 4, 0);
  414.                     stack = 4;
  415.                     break;
  416.                 case 13:    // SCSIMsgOut
  417.                     WriteMacInt16(r->a[7] + 2, 0);
  418.                     stack = 2;
  419.                     break;
  420.                 case 14:    // SCSIMgrBusy
  421.                     WriteMacInt16(r->a[7], SCSIMgrBusy());
  422.                     stack = 0;
  423.                     break;
  424.                 default:
  425.                     printf("FATAL: SCSIDispatch(%d): illegal selector\n", sel);
  426.                     QuitEmulator();
  427.                     break;
  428.             }
  429.             r->a[0] = ret;            // "rtd" emulation, a0 = return address, a1 = new stack pointer
  430.             r->a[1] = r->a[7] + stack;
  431.             break;
  432.         }
  433.  
  434.         case M68K_EMUL_OP_IRQ:            // Level 1 interrupt
  435.             r->d[0] = 0;
  436.  
  437.             if (InterruptFlags & INTFLAG_60HZ) {
  438.                 ClearInterruptFlag(INTFLAG_60HZ);
  439.                 if (HasMacStarted()) {
  440.  
  441.                     // Mac has started, execute all 60Hz interrupt functions
  442.                     ADBInterrupt();
  443.                     TimerInterrupt();
  444.                     VideoInterrupt();
  445.  
  446.                     // Call DoVBLTask(0)
  447.                     if (ROMVersion == ROM_VERSION_32) {
  448.                         M68kRegisters r2;
  449.                         r2.d[0] = 0;
  450.                         Execute68kTrap(0xa072, &r2);
  451.                     }
  452.  
  453.                     r->d[0] = 1;            // Flag: 68k interrupt routine executes VBLTasks etc.
  454.                 }
  455.             }
  456.  
  457.             if (InterruptFlags & INTFLAG_1HZ) {
  458.                 ClearInterruptFlag(INTFLAG_1HZ);
  459.  
  460.                 if (HasMacStarted()) {
  461.                     SonyInterrupt();
  462.                     DiskInterrupt();
  463.                     CDROMInterrupt();
  464.                 }
  465.             }
  466.  
  467.             if (InterruptFlags & INTFLAG_SERIAL) {
  468.                 ClearInterruptFlag(INTFLAG_SERIAL);
  469.                 SerialInterrupt();
  470.             }
  471.  
  472.             if (InterruptFlags & INTFLAG_ETHER) {
  473.                 ClearInterruptFlag(INTFLAG_ETHER);
  474.                 EtherInterrupt();
  475.             }
  476.  
  477.             if (InterruptFlags & INTFLAG_AUDIO) {
  478.                 ClearInterruptFlag(INTFLAG_AUDIO);
  479.                 AudioInterrupt();
  480.             }
  481.  
  482.             if (InterruptFlags & INTFLAG_NMI) {
  483.                 ClearInterruptFlag(INTFLAG_NMI);
  484.                 if (HasMacStarted()) {
  485.                     TriggerNMI();
  486.                 }
  487.             }
  488.             break;
  489.  
  490.         case M68K_EMUL_OP_PUT_SCRAP: {        // PutScrap() patch
  491.             void *scrap = Mac2HostAddr(ReadMacInt32(r->a[7] + 4));
  492.             uint32 type = ReadMacInt32(r->a[7] + 8);
  493.             int32 length = ReadMacInt32(r->a[7] + 12);
  494.             PutScrap(type, scrap, length);
  495.             break;
  496.         }
  497.  
  498.         case M68K_EMUL_OP_CHECKLOAD: {        // vCheckLoad() patch (resource loader)
  499.             uint32 type = r->d[1];
  500.             int16 id = ReadMacInt16(r->a[2]);
  501.             if (r->a[0] == 0)
  502.                 break;
  503.             uint32 adr = ReadMacInt32(r->a[0]);
  504.             if (adr == 0)
  505.                 break;
  506.             uint8 *p = Mac2HostAddr(adr);
  507.             uint32 size = ReadMacInt32(adr - 8) & 0xffffff;
  508.             CheckLoad(type, id, p, size);
  509.             break;
  510.         }
  511.  
  512.         case M68K_EMUL_OP_AUDIO:            // Audio component dispatch function
  513.             r->d[0] = AudioDispatch(r->a[3], r->a[4]);
  514.             break;
  515.  
  516. #if SUPPORTS_EXTFS
  517.         case M68K_EMUL_OP_EXTFS_COMM:        // External file system routines
  518.             WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4)));
  519.             break;
  520.  
  521.         case M68K_EMUL_OP_EXTFS_HFS:
  522.             WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4)));
  523.             break;
  524. #endif
  525.  
  526.         case M68K_EMUL_OP_BLOCK_MOVE:        // BlockMove() cache flushing
  527.             FlushCodeCache(Mac2HostAddr(r->a[0]), r->a[1]);
  528.             break;
  529.  
  530.         case M68K_EMUL_OP_DEBUGUTIL:
  531.         //    printf("DebugUtil d0=%08lx  a5=%08lx\n", r->d[0], r->a[5]);
  532.             r->d[0] = DebugUtil(r->d[0]);
  533.             break;
  534.  
  535.         default:
  536.             printf("FATAL: EMUL_OP called with bogus opcode %08x\n", opcode);
  537.             printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n"
  538.                    "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n"
  539.                    "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n"
  540.                    "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n"
  541.                    "sr %04x\n",
  542.                    r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7],
  543.                    r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7],
  544.                    r->sr);
  545. #ifdef ENABLE_MON
  546.             char *arg[4] = {"mon", "-m", "-r", NULL};
  547.             mon(3, arg);
  548. #endif
  549.             QuitEmulator();
  550.             break;
  551.     }
  552. }
  553.